package com.hailiang.saas.auth.service;

import com.alibaba.fastjson.JSON;
import com.hailiang.mp.commonsource.api.CommonResult;
import com.hailiang.saas.auth.common.Constant;
import com.hailiang.saas.auth.common.DefaultUserDetails;
import com.hailiang.saas.auth.config.AuthenticationConfig;
import com.hailiang.saas.auth.remote.feign.manage.UcAccountServiceApiManage;
import com.hailiang.saas.auth.remote.feign.manage.UcUserInfoServiceApiManage;
import com.hailiang.saas.auth.remote.feign.manage.UcUserRoleServiceApiManage;
import com.hailiang.saas.auth.vo.LoginAuthProtocol;
import com.hailiang.saas.uc.api.vo.UcAccountVO;
import com.hailiang.saas.uc.api.vo.UcUserInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author : pangfuzhong
 * @description
 * @date : 2021/9/25 16:04
 */
@Slf4j
public class CommonService {

    public static CommonResult createResult() {
        CommonResult commonResult = new CommonResult();
        commonResult.setSuccess(Boolean.TRUE);
        commonResult.setMsg("处理成功");
        commonResult.setErrorCode("");
        commonResult.setObject(null);
        return commonResult;
    }

    public static void returnResponse(HttpServletResponse response, CommonResult commonResult) {
        response.setContentType(Constant.APPLICATION_JSON);
        response.setCharacterEncoding(Constant.CHARACTER_ENCODING_UTF8);
        try {
            response.getWriter().write(JSON.toJSONString(commonResult));
            response.getWriter().flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static DefaultUserDetails loadUserByUsername(AuthenticationConfig authenticationConfig, String accountName) {
        DefaultUserDetails defaultUserDetails = new DefaultUserDetails();

        try {
            // 1、获取账户信息
            UcAccountServiceApiManage ucAccountServiceApiManage = authenticationConfig.getUcAccountServiceApiManage();
            CommonResult<UcAccountVO> cr = ucAccountServiceApiManage.getAccountByName(accountName);
            if(!cr.isSuccess()) {
                log.info("--> 获取账号失败, {}", cr.getMsg());
                return null;
            }

            UcAccountVO ucAccountVO = cr.getObject();
            defaultUserDetails.setUserName(ucAccountVO.getAccountName());
            defaultUserDetails.setPassword(ucAccountVO.getPassword());
            defaultUserDetails.setAccountSource(ucAccountVO.getAccountSource());

            // 2、获取账号关联的用户信息
            UcUserInfoServiceApiManage ucUserInfoServiceApiManage = authenticationConfig.getUcUserInfoServiceApiManage();
            CommonResult<UcUserInfoVO> crv = ucUserInfoServiceApiManage.getUcUserInfoById(ucAccountVO.getUserId());
            if(!crv.isSuccess()) {
                log.info("--> 获取用户信息失败, {}", crv.getMsg());
                return null;
            }

            // todo 3、获取用户关联的角色权限信息
            //UcUserRoleServiceApiManage ucUserRoleServiceApiManage = (UcUserRoleServiceApiManage) authenticationConfig.getUcUserRoleServiceApiManage();
            defaultUserDetails.setUcUserInfoVO(crv.getObject());
        } catch (Exception e) {
            log.info("--> 获取账号及用户信息失败, error = {}", e.getMessage());
            throw e;
        }
        return defaultUserDetails;
    }

    /**
     * 正常业务请求认证token
     *   1、验证token是否被踢掉
     *   2、验证redis是否存在,即是否过期
     *   3、校验token的完整性，是否被篡改
     * @param accessToken
     * @param commonResult
     * @return
     * */
    public static void authenticateTokenValid(AuthenticationConfig authenticationConfig, String accessToken, CommonResult commonResult) {
        RedisTemplate redisTemplate = authenticationConfig.getRedisTemplate();
        try {
            // 1、校验token的完整性，是否被篡改  10006
            Boolean wrongFul = authenticationConfig.getJwtTokenService().verifyTokenByRSA(accessToken);
            if(!wrongFul) {
                // 以篡改
                commonResult.setSuccess(Boolean.FALSE);
                commonResult.setErrorCode(Constant.TOKEN_INVALID_WRONGFUL_CODE);
                commonResult.setMsg(Constant.TOKEN_INVALID_WRONGFUL_MSG);
                return;
            }

            // 2、验证token是否被踢掉 10004
            String key = MessageFormat.format("{0}_{1}_{2}", Constant.OFFLINE_KEY, Constant.TOKEN_KEY_PREFIX, accessToken);
            if(redisTemplate.hasKey(key)) {
                // 不为空, 已经被踢
                commonResult.setSuccess(Boolean.FALSE);
                commonResult.setErrorCode(Constant.TOKEN_INVALID_KICK_OUT_CODE);
                commonResult.setMsg(Constant.TOKEN_INVALID_KICK_OUT_MSG);
                return;
            }

            // 3、验证redis是否存在,即是否过期 10005
            key = MessageFormat.format("{0}_{1}", Constant.TOKEN_KEY_PREFIX, accessToken);
            Object obj = redisTemplate.opsForValue().get(key);
            if(Objects.isNull(obj)) {
                // 为空, 已超过token有效时间
                commonResult.setSuccess(Boolean.FALSE);
                commonResult.setErrorCode(Constant.TOKEN_INVALID_OVERDUE_CODE);
                commonResult.setMsg(Constant.TOKEN_INVALID_OVERDUE_MSG);
                return;
            } else {
                LoginAuthProtocol loginAuthProtocol = JSON.parseObject(obj.toString(), LoginAuthProtocol.class);
                commonResult.setObject(loginAuthProtocol);
            }

            // 4、token校验成功，执行续命
            redisTemplate.expire(accessToken, authenticationConfig.getTokenExpireTime(), TimeUnit.SECONDS);
        } catch (Exception e) {
            // 10007
            commonResult.setSuccess(Boolean.FALSE);
            commonResult.setErrorCode(Constant.TOKEN_CHECK_EXCEPTION_CODE);
            commonResult.setMsg(Constant.TOKEN_CHECK_EXCEPTION_MSG + ", " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 登出过程验证token是否有效
     * @param authenticationConfig
     * @param accessToken
     * @param commonResult
     * @return
     * */
    public static void logoutAuthenticateTokenValid(AuthenticationConfig authenticationConfig, String accessToken, CommonResult commonResult) {
        try {
            Boolean wrongFul = authenticationConfig.getJwtTokenService().verifyTokenByRSA(accessToken);
            if(!wrongFul) {
                // 不合法
                commonResult.setSuccess(Boolean.FALSE);
                commonResult.setErrorCode(Constant.TOKEN_INVALID_WRONGFUL_CODE);
                commonResult.setMsg(Constant.TOKEN_INVALID_WRONGFUL_MSG);
                return;
            }
        } catch (Exception e) {
            // 10007
            commonResult.setSuccess(Boolean.FALSE);
            commonResult.setErrorCode(Constant.TOKEN_CHECK_EXCEPTION_CODE);
            commonResult.setMsg(Constant.TOKEN_CHECK_EXCEPTION_MSG + ", " + e.getMessage());
            e.printStackTrace();
        }
    }
}
